/* d_porter.c
*	Client user program of distributed Porter in a train simulation
*	
*	Simulates a Porter
*/
 
#include "syscall.h"

const int NUMBER_OF_PORTERS = 3; /*How many Porters on the Train*/

/* Lock */
int waitingForPortersLock;
int porterLuggageLock[3];
int signalPortersLock;

/* CV */
int waitingForPorters;
int porterLine[3];
int porterLuggage[3];
int signalPorters;

/* MV */
int porterLineLength[3];
int porterAvailable[3];
int passengerBeingHelped[3];
int g_porterIndex;
int porterBroadcast;
int numNeedHelpWithLuggage;

void Porter(void);
void Dummy(void);
void setupMonitors(void);
void itoa(char arr[], int size, int val);

int main(int argc, char **argv)
{
	void (*myPorter)(void);
	void (*myDummy)(void); /*For some reason if you fork just once, nothing works*/
	
	myPorter = &Porter;
	myDummy = &Dummy;
	
	setupMonitors(); /*Requesting all the locks, CVs, and MVs needed by Ticket Checker client*/
	Fork(myPorter);
	Fork(myDummy);

	Exit(0);
}

void Dummy()
{
	PrintOut("Dummy Thread\n", 13);
    Exit(0);		
}

void setupMonitors(){
	int i;
	char indexBuf[2];
	char nameBuf[4]; /*a prefix will be put in first two slots, then the local index*/
	
	for(i=0; i<NUMBER_OF_PORTERS; i++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 'l';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "pl2"*/
		porterLuggageLock[i] = CreateLock(nameBuf, 4, 1);
		
		porterLine[i] = CreateCV(nameBuf, 4, 1);
		
		porterLineLength[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'u'; /* Porter lUggage */
		porterLuggage[i] = CreateCV(nameBuf, 4, 1);
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'a'; /* Porter Avaliable */
		porterAvailable[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'h'; /* Psg Helped */
		passengerBeingHelped[i] =CreateMV(nameBuf, 4, 1);
	}
	
	waitingForPortersLock = CreateLock("wForPtsLock", 11, 1);
	signalPortersLock = CreateLock("signalPtsLock", 13, 1);
	
	waitingForPorters = CreateCV("waitingForPorters", 17, 1);
	signalPorters = CreateCV("signalPorters", 13, 1);
	
	g_porterIndex = CreateMV("g_porterIndex", 13, 1);
	porterBroadcast = CreateMV("porterBroadcastMV", 17, 1);
	numNeedHelpWithLuggage = CreateMV("numNeedHelpWithLug", 18, 1);
}

void Porter(){

	int getIntoLoop=1;
	char buf[2]; /*Print out for Porter Index*/
	char psgBuf[2];/*Print out for Passenger Index*/
	int myIdentifier = 0;
	int psgPt;
	
	myIdentifier = GetMV(g_porterIndex);
	SetMV(g_porterIndex, myIdentifier + 1);
	
	while(1){
		
		Acquire(signalPortersLock,0);
		
		Wait(signalPorters, signalPortersLock,0); /*Wait for Psg*/
		if(GetMV(porterBroadcast) ==0 || numNeedHelpWithLuggage > 0)
		{
			SetMV(porterBroadcast, 1);
			Release(signalPortersLock,0);
			Acquire(waitingForPortersLock,0);
			Wait(waitingForPorters, waitingForPortersLock,0);
			Acquire(porterLuggageLock[myIdentifier],0);
			Broadcast(waitingForPorters, waitingForPortersLock,0);
			Release(waitingForPortersLock,0);
		}
		else{
			Release(signalPortersLock,0);
			Acquire(porterLuggageLock[myIdentifier],0);
		}
		
		SetMV(porterAvailable[myIdentifier], 1);
		getIntoLoop=1;
		while(GetMV(porterLineLength[myIdentifier])>0||getIntoLoop)
		{	
			getIntoLoop=0;
			/*Wait for signal from passenger to get their luggage*/
			Wait(porterLuggage[myIdentifier], porterLuggageLock[myIdentifier],0);
			SetMV(numNeedHelpWithLuggage, GetMV(numNeedHelpWithLuggage)-1);
			itoa(buf, 2 , myIdentifier);
			itoa(psgBuf, 2, GetMV(passengerBeingHelped[myIdentifier]));
			PrintOut("Porter [",8);
			PrintOut(buf, 2);
			PrintOut("] of Train [0] picks up bags of 1st class Passenger [",53);
			PrintOut(psgBuf, 2);
			PrintOut("]\n", 2);

			Signal(porterLuggage[myIdentifier], porterLuggageLock[myIdentifier],0);
			if(GetMV(porterLineLength[myIdentifier])==0)	
				SetMV(porterAvailable[myIdentifier], 1);
			/*Or signal those remaining on the line*/
			else
			{
				Signal(porterLine[myIdentifier], porterLuggageLock[myIdentifier],0);
			}
		}
		/*Exit monitor*/
		Release(porterLuggageLock[myIdentifier],0);
		
	}
	
	Exit(0);
}
int myexp ( int count ) {
  int i, val=1;
  for (i=0; i<count; i++ ) {
    val = val * 10;
  }
  return val;
}

void itoa( char arr[], int size, int val ) {
  int i, max, dig, subval, loc;
  for (i=0; i<size; i++ ) {
    arr[i] = '\0';
  }

  for ( i=1; i<=10; i++ ) {
    if (( val / myexp(i) ) == 0 ) {
      max = i-1;
      break;
    }
  }

  subval = 0;
  loc = 0;
  for ( i=max; i>=0; i-- ) {
    dig = 48 + ((val-subval) / myexp(i));
    subval += (dig-48) * myexp(i);
    arr[loc] = dig;
    loc++;
  }

  return;
}